
#ifndef __avmplus_avmnative_hpp__
#define __avmplus_avmnative_hpp__

#define DEV_BIND extern "C" __declspec(dllexport) 

#include "avmrt.h"
#include "avmrt-bind.h"

namespace avmnative
{

	enum EInternal             {EC_Internal};
	
	struct GUID
	{
		DWORD A,B,C,D;

		GUID( DWORD A, DWORD B, DWORD C, DWORD D )
		{
			this->A = A;
			this->B = B;
			this->C = C;
			this->D = D;

		}
	};

	class IUnknown
	{
	public:
		virtual DWORD STDCALL queryInterface( const GUID& RefIID, void** InterfacePtr ) { (void)RefIID; (void)InterfacePtr; return 0;}
		virtual DWORD STDCALL addRef() {return 0;}
		virtual DWORD STDCALL release() {return 0;}
	};

	class Class;
	
	class Object : public IUnknown
	{
	public:		
		virtual GlobalMemoryProvider* _getGlobalMemoryProvider() { return NULL; }

	public:
		virtual ~Object() 
		{ 
			//printf( "aaa" );
		};

		void* operator new( size_t Size, EInternal* mem ) 
		{ 
			(void)Size;
			return (void*)mem; 
		}
		
		void operator delete (void *object,EInternal* mem)
		{
			(void)object;
			(void*)mem;
		}
		
		static void createInstance( avmnative::EInternal *p )
		{
			new (p) avmnative::Object();
		}

		class NativeSlots
		{

		};

		inline ScriptObject *self()
		{
			return (ScriptObject*)::avm_gc_findBeginning( this );
		}

		inline Atom atom()
		{
			return ::avmbind_Object_atom( self() );
		};
		
	};

	class ClassInfo
	{
	public:
		typedef void* (*StaticConstructorType)();
		typedef void* (*InternalConstructorType)(void *p);
		
		StaticConstructorType classStaticConstructor;
		InternalConstructorType objectInternalConstructor;

		int sizeofInstance;
		int sizeofClass;

		int offsetofInstance;
		int offsetofClass;

		int proxy;

		ClassInfo( int size, int classSize, void *staticConstructor, void *internalConstructor, int inProxy = 0 )
		{
			classStaticConstructor = (StaticConstructorType)staticConstructor;
			objectInternalConstructor = (InternalConstructorType)internalConstructor;

			sizeofInstance = size;
			sizeofClass = classSize;

			//superClass = super;

			proxy = inProxy;

		}		
		
		ClassInfo( int size, int oInstance, int classSize, int oClass, void *staticConstructor, void *internalConstructor, int inProxy = 0 )
		{
			classStaticConstructor = (StaticConstructorType)staticConstructor;
			objectInternalConstructor = (InternalConstructorType)internalConstructor;

			sizeofInstance = size;
			sizeofClass = classSize;

			offsetofClass = oClass;
			offsetofInstance = oInstance;

			proxy = inProxy;

			//superClass = super;

		}


	};

	
	class Class : public Object
	{
	public:		

		static void createInstance( avmnative::EInternal *p )
		{
			new (p) avmnative::Class();
		}

		virtual ~Class() 
		{ 
		};

	};

}

#define DECLARE_OBJECT( classname, superclassname ) \
	typedef superclassname superclass; \
	static void createInstance( avmnative::EInternal *p ) { new (p) classname(); } \


#define BIND_OFFSET( classname, field ) (int)(&((classname*)(0))->field)

#define BIND_OBJECT_AND_CLASS( objclassname, objslotoffset, clsclassname, classslotoffset ) \
	avmnative::ClassInfo classinfo_##objclassname##( sizeof(objclassname), objslotoffset, sizeof(clsclassname) , classslotoffset, objclassname::createInstance, clsclassname::createInstance ); \
	DEV_BIND avmnative::ClassInfo *autoclass_##objclassname##$ = &classinfo_##objclassname##;

#define BIND_CUSTOM_OBJECT( name, classname, objslotoffset ) \
	avmnative::ClassInfo classinfo_##name##( sizeof(classname), objslotoffset, 0 , 0, NULL, classname::createInstance ); \
	DEV_BIND avmnative::ClassInfo *autoclass_##name##$ = &classinfo_##name##;

#define BIND_PROXY_OBJECT( classname, objslotoffset ) \
	avmnative::ClassInfo classinfo_##classname##( sizeof(classname), objslotoffset, 0 , 0, NULL, classname::createInstance, 1 ); \
	DEV_BIND avmnative::ClassInfo *autoclass_##classname##$ = &classinfo_##classname##;

//bind object with slots starting from end of avmnative::Object
#define BIND_OBJECT( classname ) \
	BIND_CUSTOM_OBJECT( classname, classname, sizeof(classname::superclass) )

//bind fully native object with no slots
#define BIND_NATIVE_OBJECT( classname ) \
	BIND_CUSTOM_OBJECT( classname, classname, sizeof(classname) )

//bind fully object with slots
#define BIND_MIXED_OBJECT( classname, objslotoffset ) \
	BIND_CUSTOM_OBJECT( classname, classname, objslotoffset )

#define BIND_CUSTOM_METHOD_(cls,func,name, rettype ) \
	extern "C" DEV_BIND rettype (##cls::*func_##cls####name)( uint32_t argc, AvmBox* argv ); \
	DEV_BIND rettype (##cls::*func_##cls####name)( uint32_t argc, AvmBox* argv ) = &##cls::func; 

#define BIND_CUSTOM_METHOD(cls,func,name ) \
	BIND_CUSTOM_METHOD_(cls,func,name,AvmBox);

#define BIND_METHOD(cls,func) \
	BIND_CUSTOM_METHOD_(cls,func,func,AvmBox)

#define BIND_CUSTOM_STATIC_METHOD(cls,func,name) \
	extern "C" DEV_BIND AvmBox (*func_##cls##$##name)( uint32_t argc, AvmBox* argv ); \
	DEV_BIND Atom (*func_##cls##$##name)( uint32_t argc, AvmBox* argv ) = &##cls::func;

#define BIND_STATIC_METHOD(cls,func) \
	BIND_CUSTOM_STATIC_METHOD(cls,func,func)

#define BIND_FUNCTION(func) \
	extern "C" DEV_BIND AvmBox (*func_##func)( uint32_t argc, AvmBox* argv ); \
	DEV_BIND Atom (*func_##func)( uint32_t argc, AvmBox* argv ) = &func; 

#endif